395 至少有 K 个重复字符的最长子串 
给你一个字符串  s  和一个整数  k  ,请你找出  s  中的最长子串, 要求该子串中的每一字符出现次数都不少于  k  。返回这一子串的长度。
如果不存在这样的子字符串,则返回 0。
示例 1:
** 输入:**s = "aaabb", k = 3 ** 输出:**3 ** 解释:** 最长子串为 "aaa" ,其中 'a' 重复了 3 次。
示例 2:
** 输入:**s = "ababbc", k = 2 ** 输出:**5 ** 解释:** 最长子串为 "ababb" ,其中 'a' 重复了 2 次, 'b' 重复了 3 次。
递归函数的含义:函数入参 s 是表示源字符串;k 是限制条件,即子字符串中每个字符最少出现的次数;函数返回结果是满足题意的最长子字符串长度。 递归的终止条件(base case):如果字符串 s 的长度少于 k,那么一定不存在满足题意的子字符串,返回 0; 怎样分解子问题:如果一个字符 c 在 s 中出现的次数少于 k 次,那么 s 中所有的包含 c 的子字符串都不能满足题意,因此应该在 s 的所有不包含 c 的子字符串中去寻找结果
js
/**
 * @param {string} s
 * @param {number} k
 * @return {number}
 */
var longestSubstring = function (s, k) {
    // base case 如果源字符串比限制长度k还要小,肯定即便s中所有字符都是同一个也不满足条件
    if (s.length < k) return 0;
    // 源字符串中每个字符出现的次数存入map中
    let counter = new Map();
    for (let i = 0; i < s.length; i++) {
        counter.set(s[i], (counter.get(s[i]) || 0) + 1);
    }
    for (let c of counter.keys()) {
        // 字符 c 在 s 中出现的次数少于 k 次,s中所有包含c的子字符串都不能满足
        if (counter.get(c) < k) {
            // 应该在s中所有不包含c的子字符串中查找
            let count = 0;
            for (let t of s.split(c)) {
                count = Math.max(count, longestSubstring(t, k));
            }
            return count;
        }
    }
    return s.length;
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26